Skip to content

Fix the web focus highlight on YouTube, and show it only for key navigation - #842

Merged
AndreyPavlenko merged 3 commits into
AndreyPavlenko:masterfrom
giunatale:fix/youtube-focus-highlight
Nov 10, 2026
Merged

AndreyPavlenko merged 3 commits into
AndreyPavlenko:masterfrom
giunatale:fix/youtube-focus-highlight

Conversation

@giunatale

Copy link
Copy Markdown
Contributor

The focus highlight (the outline showing which element is selected when navigating with a D-pad or a car's rotary controller) never worked on YouTube. Two commits:

  • Fix the focus highlight on pages that require Trusted Types. addFocusHighlight() set the style through innerHTML, which YouTube blocks: every page load logged Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment, and nothing was highlighted. It now sets the style's textContent, which Trusted Types doesn't restrict.
  • Show the focus highlight only for key navigation. Once working, the highlight outlined whatever was last tapped, and a page that focuses an element when it loads (YouTube focuses its logo) got it before anything was pressed. The style is now added only after the first navigation key (D-pad, rotary controller, arrow keys), and uses :focus-visible, so taps after that aren't outlined either.

Tested on a OnePlus 12 (Android 16) by inspecting Fermata's WebView: no console error, no outline when the page loads or after taps, and the outline appearing and moving through the page with adb shell input keyevent KEYCODE_DPAD_DOWN.

@AndreyPavlenko AndreyPavlenko left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review of the textContent fix and the key-navigation gate.

Correct

  • innerHTML to textContent fixes the Trusted Types error.
  • :focus-visible plus the key gate is reasonable. Keep the gate, since a script that focuses an element on load can still match :focus-visible.

Issues

  1. Filter accepts almost any key. !event.isSystem() lets letters, digits, Enter and Space through, so typing in a search box turns the highlight on. The comment and description say "navigation key", but the code does not check for one. Restrict to navigation keys, e.g. KEYCODE_DPAD_UP/DOWN/LEFT/RIGHT, KEYCODE_DPAD_CENTER, KEYCODE_TAB.
  2. Rotary input may not reach dispatchKeyEvent. Some rotary controllers send MotionEvent ACTION_SCROLL (AXIS_SCROLL) instead of key events. Testing used adb input keyevent only. Verify on real car hardware, or also handle dispatchGenericMotionEvent.
  3. Duplicate <style> elements. The style is added on every pageLoaded, and YouTube is an SPA, so pageLoaded can fire repeatedly on one document. Give the element an id and skip if present:
    if (document.getElementById('fermata-focus')) return;
    style.id = 'fermata-focus';
  4. Minor: if the first key arrives during page load, document.head may be null. Use (document.head || document.documentElement).
  5. Minor: keyNavigation never resets for the view's lifetime. Probably intended, but make it a deliberate choice.

Verdict: request changes for 1 and 3. Item 2 needs hardware testing or an explicit note that it is untested.

Reviewed by Claude

YouTube only accepts TrustedHTML for innerHTML, so injecting the focus
highlight style threw on every page load and focused elements were not
highlighted. Set the style's textContent instead.
Once working, the highlight outlined whatever was last tapped, and a
page that focuses an element when it loads (YouTube focuses its logo)
got it before anything was pressed. Add the style only once a
navigation key (D-pad, rotary controller, arrow keys) has been pressed,
and use :focus-visible so taps after that aren't outlined either.
Only navigation keys (D-pad, Tab, rotary next/previous) and rotary scroll events turn it on, rather than any key, so typing doesn't. The style gets an id and isn't added again to the same document, and it falls back to the document element while the head doesn't exist yet.
@giunatale
giunatale force-pushed the fix/youtube-focus-highlight branch from bde54b3 to 9d7818b Compare November 8, 2026 15:47
@giunatale

Copy link
Copy Markdown
Contributor Author

Review of the textContent fix and the key-navigation gate.

Correct

  • innerHTML to textContent fixes the Trusted Types error.
  • :focus-visible plus the key gate is reasonable. Keep the gate, since a script that focuses an element on load can still match :focus-visible.

Issues

  1. Filter accepts almost any key. !event.isSystem() lets letters, digits, Enter and Space through, so typing in a search box turns the highlight on. The comment and description say "navigation key", but the code does not check for one. Restrict to navigation keys, e.g. KEYCODE_DPAD_UP/DOWN/LEFT/RIGHT, KEYCODE_DPAD_CENTER, KEYCODE_TAB.
  2. Rotary input may not reach dispatchKeyEvent. Some rotary controllers send MotionEvent ACTION_SCROLL (AXIS_SCROLL) instead of key events. Testing used adb input keyevent only. Verify on real car hardware, or also handle dispatchGenericMotionEvent.
  3. Duplicate <style> elements. The style is added on every pageLoaded, and YouTube is an SPA, so pageLoaded can fire repeatedly on one document. Give the element an id and skip if present:
    if (document.getElementById('fermata-focus')) return;
    style.id = 'fermata-focus';
  4. Minor: if the first key arrives during page load, document.head may be null. Use (document.head || document.documentElement).
  5. Minor: keyNavigation never resets for the view's lifetime. Probably intended, but make it a deliberate choice.

Verdict: request changes for 1 and 3. Item 2 needs hardware testing or an explicit note that it is untested.

Reviewed by Claude

Thanks! Addressed basically everything:

  1. Filter: only navigation input turns the highlight on now: KEYCODE_DPAD_UP/DOWN/LEFT/RIGHT, KEYCODE_DPAD_CENTER, KEYCODE_TAB and KEYCODE_NAVIGATE_NEXT/PREVIOUS. Typing no longer does.
  2. Rotary: dispatchGenericMotionEvent also turns it on for ACTION_SCROLL from SOURCE_ROTARY_ENCODER. Untested on hardware: my car only has a touch screen, so this part is tested with adb input keyevent only.
  3. Duplicate <style>: the element has the id fermata-focus and isn't added again if it's there.
  4. document.head: falls back to document.documentElement.
  5. keyNavigation never resets: intended. Whoever navigated with keys keeps using the same controller, so it stays on for the view's lifetime; the comment now says so.

Also rebased on master.

@AndreyPavlenko
AndreyPavlenko merged commit 900177e into AndreyPavlenko:master Nov 10, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants